open Num;; 

let int n = `Int(Int n);;
 
let ( +: ) f g = `Add(f, g) and ( *: ) f g = `Mul(f, g);; 

let expr = 
    `Var "x" *: ((int 12 *: int 0 +: (int 23 +: int 8)) +: `Var "y");; 

let time f x = 
    let t = Sys.time() in 
    let f_x = f x in 
    Printf.printf "Took %fs\n" (Sys.time() -. t); 
    f_x;; 

let rec loop n f x = if n=1 then f x else (ignore(f x); loop (n-1) f x);; 

let rec ( +: ) f g = match f, g with 
    | `Int n, `Int m -> `Int (n +/ m) 
    | `Int (Int 0), e | e, `Int (Int 0) -> e 
    | f, `Add(g, h) -> f +: g +: h 
    | f, g -> `Add(f, g);; 

let rec ( *: ) f g = match f, g with 
    | `Int n, `Int m -> `Int (n */ m) 
    | `Int (Int 0), e | e, `Int (Int 0) -> `Int (Int 0) 
    | `Int (Int 1), e | e, `Int (Int 1) -> e 
    | f, `Mul(g, h) -> f *: g *: h 
    | f, g -> `Mul(f, g);; 

let rec simplify = function 
    | `Int _ | `Var _ as f -> f 
    | `Add (f, g) -> simplify f +: simplify g 
    | `Mul (f, g) -> simplify f *: simplify g;;   

time (loop 1000000 simplify) expr;; 
   
 
